package com.lagou.factory;

import com.lagou.annotation.Transactional;
import com.lagou.utils.AopTargetUtils;
import com.lagou.utils.ConnectionUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;

/**
 * <pre>
 * 描述：TODO
 * </pre>
 *
 * @类名：com.lagou.proxy.ProxyFactory
 * @作者 mengwei
 * 创建日期：2020/10/15 11:12
 */
public class TransactionalProxyFactory {
    private TransactionalProxyFactory() {
    }

    private static final String PROXY_JDK="JDK";
    private static final String PROXY_CGLIB="CGLIB";
    private static TransactionalProxyFactory proxyFactory = new TransactionalProxyFactory();

    public static TransactionalProxyFactory newInstance() {
        return proxyFactory;
    }

    public <T> T getProxy(T obj) {
        T result = null;
        if (obj.getClass().getInterfaces().length>0){
//            有实现接口，使用jdk代理
            result= getJdkProxy(obj);
        }else {
//            使用cglibdialing
            result= getCglibProxy(obj);
        }

        return result;
    }
    public <T> T getProxy(T obj,String proxyType) {
        T result = null;
        switch (proxyType){
            case PROXY_CGLIB:return getCglibProxy(obj);
            case PROXY_JDK:return getJdkProxy(obj);
            default:;
        }
        return result;
    }



    private  <T> T getJdkProxy(T obj) {

        return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), (proxy, method, args) -> {
            Object invoke = null;
//         如果有Transactional注解，则使用增强代理,但是代理后的类
            Object target = AopTargetUtils.getTarget(obj);
            Method sourceMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
            Transactional annotation = sourceMethod.getAnnotation(Transactional.class);
            System.out.println(annotation);
            if (!Objects.isNull(annotation)) {
                ConnectionUtils.getInstance().getCurrentConnection().setAutoCommit(false);
                try {
                    invoke = method.invoke(obj, args);
                    ConnectionUtils.getInstance().getCurrentConnection().commit();

                } catch (Exception e) {
                    ConnectionUtils.getInstance().getCurrentConnection().rollback();
                    System.out.println("rollback");
                    throw e;
                }
            } else {
                invoke = method.invoke(obj, args);
            }
            return invoke;
        });

    }

    private <T> T getCglibProxy(T obj) {

        return (T) Enhancer.create(obj.getClass(), (MethodInterceptor) (o, method, objects, methodProxy) -> {
            Object invoke = null;
//         如果有Transactional注解，则使用增强代理
            if (!Objects.isNull(method.getAnnotation(Transactional.class))) {
                ConnectionUtils.getInstance().getCurrentConnection().setAutoCommit(false);
                try {
                    invoke = method.invoke(obj, objects);
                    ConnectionUtils.getInstance().getCurrentConnection().commit();

                } catch (Exception e) {
                    ConnectionUtils.getInstance().getCurrentConnection().rollback();
                    System.out.println("rollback");

                    throw e;
                }
            } else {
                invoke = method.invoke(obj, objects);
            }

            return invoke;
        });

    }


}
